package com.zkh.myutils.json;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.zkh.myutils.bean.BeanBaseTypeConverter;
import com.zkh.myutils.bean.TypeConverter;
import com.zkh.myutils.code.CoderUtils;
import com.zkh.myutils.utils.Assert;
import com.zkh.myutils.utils.Regexp;
import com.zkh.myutils.utils.TypeUtils;

public final class JSONObject extends JSON{

	/**
	 * 内部存储Map
	 */
	protected Map<String, Object> jsonObjectMap = new LinkedHashMap<String, Object>();
	
	/**
	 * 私有构造器，内部调用
	 */
	private JSONObject(Map<String, Object> jsonObjectMap) {
		this.jsonObjectMap = jsonObjectMap;
	}
	
	/**
	 * JSON对象构造器
	 * @param obj 待转换的对象。可为json字符串（json字符串转对象）和非字符串对象（对象转json字符串）
	 * @return
	 */
	public JSONObject(Object obj) {
		this(obj, null);
	}
	
	/**
	 * JSON对象构造器
	 * @param obj 待转换的对象。可为json字符串（json字符串转对象）和非字符串对象（对象转json字符串）
	 * @param converter 转换器，自定义转换方法
	 * @return
	 */
	public JSONObject(Object obj, TypeConverter converter) {
		//解析器
		this.converter = converter==null ? new TypeConverter() : converter;
		//不为空
		if(obj!=null) {
			//字符串
			if(obj instanceof String) {
				if(Regexp.isMatch("\\s*\\{.*\\}\\s*", obj.toString())) {
					//解析字符串
					jsonObjectMap = JSONStringParser.parseToMap(TypeUtils.toWrap(CoderUtils.decodeUnicode(obj.toString()).toCharArray()));
				}else {
					throw new JSONParseException("字符串必须满足JSON格式");
				}
			}else if(obj instanceof Collection || obj.getClass().isArray()) {
				throw new JSONParseException("数组和集合无法转换为JSONObject对象");
			}else if(obj instanceof Map){
				//Map
				Map<?, ?> map = (Map<?, ?>) obj;
				//遍历Map
				for(Entry<?, ?> kvs : map.entrySet()) {
					jsonObjectMap.put(kvs.getKey()==null ? "null" : kvs.getKey().toString(), new JSONObjectParser(this.converter).parseObject(kvs.getValue()));
				}
			}
			//是否为不用解析的类型
			else if(isNoParseType(obj)){
				throw new JSONParseException("无法转换为JSONObject对象");
			}else {
				//剩余为可解析的对象
				jsonObjectMap = new JSONObjectParser(this.converter).parseToMap(obj);
			}
		}
	}
	
	/**
	 * 获取JSONObject对象
	 * @return
	 */
	protected static JSONObject valueOf(Map<String, Object> jsonObjectMap) {
		return new JSONObject(jsonObjectMap);
	}
	
	/**
	 * 是否为基础类型。<br>
	 * 基础类型定义（只过滤常用的类型）：<br>
	 * 1、8大基础类型及其包装类。
	 * 2、Date类型及继承Date类型的类型。
	 * 3、String类型（已单独解析，此处忽略）。
	 * 4、其它类型后续遇到后再添加。
	 * @param obj 传入参数
	 * @return
	 */
	private boolean isNoParseType(Object obj) {
		//是否是基础类型
		return BeanBaseTypeConverter.notParseType.contains(obj.getClass().getSimpleName()) || obj instanceof Date;
	}
	
	/**
	 * 是否为空
	 * @return
	 */
	public boolean isEmpty() {
		return jsonObjectMap.isEmpty();
	}
	
	/**
	 * 添加一个元素
	 */
	public void put(String key, Object value) {
		//转换器为空，初始化
		if(converter==null) {
			converter = new TypeConverter();
		}
		jsonObjectMap.put(key, new JSONObjectParser(this.converter).parseObject(value));
	}
	
	/**
	 * 移除元素
	 * @param key 键
	 */
	public void remove(String key) {
		jsonObjectMap.remove(key);
	}

	/**
	 * 获取boolean值
	 * @param key 键
	 * @return
	 */
	public boolean getBooleanValue(String key) {
		return (boolean) jsonObjectMap.get(key);
	}
	
	/**
	 * 获取数字类型
	 * @param key 键
	 * @return
	 */
	public BigDecimal getNumberValue(String key) {
		Object val = jsonObjectMap.get(key);
		return val==null ? null : new BigDecimal(val.toString());
	}
	
	/**
	 * 获取字符串类型
	 * @param key 键
	 * @return
	 */
	public String getStringValue(String key) {
		return Assert.getIfNotNull(jsonObjectMap.get(key), Object::toString);
	}
	
	/**
	 * 获取日期类型（默认可解析yyyy-MM-dd和yyyy-MM-dd HH:mm:ss）
	 * @param key 键
	 * @return 空时，返回null，不符合默认格式的，抛出异常
	 */
	public Date getDateValue(String key) {
		//格式转换
		return getDefaultDate((String) jsonObjectMap.get(key));
	}
	
	/**
	 * 获取日期类型
	 * @param key 键
	 * @param format 日期字符串格式
	 * @return 空时，返回null，不符合指定格式的，抛出异常
	 */
	public Date getDateValue(String key, String format) {
		return getDate((String) jsonObjectMap.get(key), format);
	}
	
	/**
	 * 获取JSONObject对象
	 * @param key 键
	 */
	public JSONObject getJSONObject(String key) {
		@SuppressWarnings("unchecked")
		Map<String, Object> map = (Map<String, Object>) jsonObjectMap.get(key);
		return valueOf(map);
	}
	
	/**
	 * 获取JSONArray对象
	 * @param key 键
	 * @return
	 */
	public JSONArray getJSONArray(String key) {
		@SuppressWarnings("unchecked")
		List<Object> list = (List<Object>) jsonObjectMap.get(key);
		return JSONArray.valueOf(list);
	}

	/**
	 * JSON对象转指定对象
	 * @param type 指定对象类型
	 * @return
	 */
	public <T> T parseEntity(Class<T> type) {
		return super.parseEntity(jsonObjectMap, type);
	}
	
	/**
	 * 返回json格式的字符串
	 */
	public String toString() {
		return toString(jsonObjectMap, false);
	}
	
	/**
	 * 返回json格式的字符串
	 * @param ignoreNullValueKey 是否忽略值为null的key
	 * @return
	 */
	public String toString(boolean ignoreNullValueKey) {
		return toString(jsonObjectMap, ignoreNullValueKey);
	}
}
